home *** CD-ROM | disk | FTP | other *** search
- /*
- File: MemMgrM.cpp
-
- Contains: Mac-specific implementations of MemMgr calls
-
- Owned by: Jens Alfke
-
- Copyright: © 1994 - 1997 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- <5> 1/8/97 DH 1401434: Properly handle low mem for
- MMSetHandleSize; remove redunant low-mem
- check in MMCopyHandle; check for low-mem
- after handle allocations in the app heap.
- <4> 27.09.1996 NP 1386083: New routines and changes to
- MMSetHandleSize and MMAllocateHnadleIn
- <3> 9/19/96 DH Task: low memory changes,1377922,1377888.
- MMSystemFreeSpace now returns true
- number.OutOfAvailMem checks for out of free
- mem and tracks low mem.
- <2> 9/13/96 jpa 115386: Optimize MMSystemFreeSpace by
- caching a temp handle.
- <10> 10/24/95 jpa 1293441: Added slush-fund. Allocate
- temp-mem handles out of app heap if
- absolutely necessary.
- <9> 10/4/95 jpa MMCopyHandle allocates in current heap's
- area. [1289074]
- <8> 5/5/95 TJ jpa: ApplicZone --> ApplicationZone.
- <7> 5/4/95 jpa Added free-space fns, and maintain a
- certain minimum free space in handle
- allocation ops [1235657]
- <6> 1/25/95 jpa Removed HandToHand workaround now that
- we're on Dagon a2. [1209733]
- <5> 1/12/95 jpa Took out five-dollar-sign mark and added
- Radar bug 1209733. [1210981]
- <4> 12/5/94 jpa Nuked errant pragma lib_export's. [1195676]
- <3> 10/12/94 JA Added 68k workaround for HandToHand; no
- effect on PPC build.
- <2> 9/29/94 RA 1189812: Mods for 68K build.
- <1> 9/14/94 jpa first checked in
-
- To Do:
- In Progress:
-
- */
-
-
- #ifndef _MEMMGR_
- #include "MemMgr.h"
- #endif
-
- #ifndef _MEMMGRPV_
- #include "MemMgrPv.h"
- #endif
-
- #ifndef _MEMDEBG_
- #include "MemDebg.h"
- #endif
-
- #ifndef __MEMORY__
- #include <Memory.h> // Mac memory manager
- #endif
-
- #ifndef __ERRORS__
- #include <Errors.h>
- #endif
-
-
- const size_t kMaxHandleBlockSize = 0x7FFFFFFF;
-
- #if MM_DEBUG
- const size_t kTempMemFudge = 1000*1024;
- #else
- const size_t kTempMemFudge = 100*1024;
- #endif
-
-
- size_t gHandleMemFullMark = 0; // 0 means no mark.
-
-
-
- static void MMSystemFreeSpace( Zone *zone, size_t *total, size_t *contig );
- static size_t GetFreeTempMemAndAppMem();
-
-
- static mmboolean
- FreeSpaceLow( MMHandle h )
- {
- if( !h )
- return kMMFalse;
- Zone *zone = ::HandleZone((Handle)h);
- if( MemError() )
- return kMMTrue;
- size_t free,contig;
- MMSystemFreeSpace(zone,&free,&contig);
- return (free < kPlatformMinFreeSpace || contig < kPlatformMinContigSpace);
- }
-
- static MMBoolean OutOfAvailableMemoryForHandle( MMHandle h, size_t size )
- {
- // This function returns a boolean that signifies, given the block
- // we have allocated, whether we are now out of free memory. We have to do
- // an after the fact check because temp mem cannot be reliably checked before
- // allocation (i.e. another allocation may have already taken place in the
- // time after we decided that we had enough free memory, and the actual allocation
- // takes place, etc.)
-
- if( !h )
- return kMMFalse;
- Zone *zone = ::HandleZone((Handle)h);
- if( MemError() )
- return kMMTrue;
- size_t free,contig;
- MMSystemFreeSpace(zone,&free,&contig);
-
- // In the system there are two points of low memory.
- // 1. Out of memory threshold.
- // • Once this amount of total/contig free space is reached, no more allocations
- // will be honored.
- // 2. Low space threshhold.
- // • When memory is under this threshold, only allocations that don't take
- // up the rest of free space wiill succeed. The size of the block that will
- // succeed is based upon what percentage of the free space it will take up.
- if( free < kPlatformMinFreeSpace || contig < kPlatformMinContigSpace )
- return kMMFalse;
- if( free < kPlatformLowTotalSpace || contig < kPlatformLowContigSpace )
- if ( size/free < kMinFreeRatio )
- return kMMTrue;
- return kMMFalse;
- }
-
- static Zone*
- TempMemZone( )
- {
- // The only reliable way to get the Process Manager (temp-mem) zone is to call
- // HandleZone on a temp handle. To avoid the overhead of allocating a handle
- // every time, keep a tiny one around as a static variable.
-
- static Handle sTempMemHandle = NULL;
-
- if( !sTempMemHandle ) {
- OSErr err;
- sTempMemHandle = ::TempNewHandle(0,&err);
- if( err ) {
- MM_WARN("Eek, couldn't allocate hdl to find temp-mem zone!");
- return kMMNULL;
- }
- }
- return ::HandleZone(sTempMemHandle);
- }
-
-
- //========================================================================================
- // OPERATIONS ON RELOCATABLE BLOCKS (HANDLES)
- //========================================================================================
-
-
- //----------------------------------------------------------------------------------------
- // MMAllocateHandle
- //----------------------------------------------------------------------------------------
-
- MMHandle MMAllocateHandle(size_t howBig)
- {
- return MMAllocateHandleIn(howBig,gDefaultHeap->GetLocation());
- }
-
- //----------------------------------------------------------------------------------------
- // MMAllocateHandleIn
- //----------------------------------------------------------------------------------------
-
- MMHandle MMAllocateHandleIn(size_t size, MMHeapLocation loc)
- {
- #if MM_DEBUG
- if (GetFreeTempMemAndAppMem() + size < gHandleMemFullMark)
- return 0;
- #endif
-
- #if MMDebug
- if( size>kMaxHandleBlockSize ) {
- MM_WARN("Bogus size 0x%08lx for MMAllocateHandle",size);
- return kMMNULL;
- }
- #endif
-
- Handle handle;
- OSErr err;
-
- switch( loc ) {
- case kMMSysMemory:
- handle = ::NewHandleSys(size);
- err = MemError();
- break;
- case kMMAppMemory:
- SetZone(ApplicationZone());
- handle = ::NewHandle(size);
- err = MemError();
- break;
- case kMMTempMemory:
- handle = ::TempNewHandle(size, &err);
- break;
- default:
- MM_WARN("MMAllocateHandleIn: Bogus memory source!");
- return 0;
- }
-
- if( err!=noErr && err!=memFullErr )
- MM_WARN("MMAllocateHandle got err %d",err);
-
- if (OutOfAvailableMemoryForHandle( handle, size ) )
- {
- MMFreeHandle(handle);
- handle = kMMNULL;
- }
-
- if( handle == kMMNULL && loc==kMMTempMemory ) {
- // Allow temp-mem handle to be allocated out of app heap if there's room.
- // It's easy for temp-mem to become totally wedged (just launch an app whose
- // "preferred size" is greater than the amount available), which would
- // otherwise totally prevent allocation of handles.
- handle = (Handle) MMAllocateHandleIn(size,kMMAppMemory);
- if (OutOfAvailableMemoryForHandle( handle, size ) )
- {
- MMFreeHandle(handle);
- handle = kMMNULL;
- }
- }
-
- #if MMDebug
- if( gValidate>0 && handle )
- Zap(*(Handle)handle, size, 0xBBBBBBBB);
- #endif
-
- return (MMHandle) handle;
- }
-
- //----------------------------------------------------------------------------------------
- // MMFreeHandle
- //----------------------------------------------------------------------------------------
-
- void MMFreeHandle(MMHandle handle)
- {
- if( handle != kMMNULL ) {
- #if MMDebug
- if( gValidate>0 ) {
- if( !MMValidateHandle(handle) )
- return;
- Zap(*(Handle)handle, GetHandleSize((Handle)handle), 0xDD);
- }
-
- if( HGetState((Handle)handle) & 0x20 ) {
- MM_WARN("MMFreeHandle: Tried to dispose rsrc %p",handle);
- return;
- }
- #endif
-
- DisposeHandle((Handle)handle);
-
- #if MMDebug
- OSErr err = MemError();
- if( err!=noErr )
- MM_WARN("MMFreeHandle: DisposeHandle returned err %d",err);
- #endif
- }
- }
-
- //----------------------------------------------------------------------------------------
- // MMCopyHandle
- //----------------------------------------------------------------------------------------
-
- MMHandle MMCopyHandle( MMHandle handle )
- {
- if( handle == kMMNULL ) {
- MM_WARN("MMCopyHandle(NULL)!");
- return kMMNULL;
- }
-
- #if MMDebug
- if( gValidate>0 )
- if( !MMValidateHandle(handle) )
- return kMMNULL;
- if( (HGetState((Handle)handle)&0x20) && !(HGetState((Handle)handle)&0x80) )
- MM_WARN("Copying purgeable handle %p",handle);
- #endif
-
- size_t size = GetHandleSize((Handle) handle);
- if( MemError() ) {
- MM_WARN("MMCopyHandle got err %d",MemError());
- return kMMNULL;
- }
-
- MMHandle copy = MMAllocateHandle(size);
- if( copy )
- PlatformCopyMemory(*(Handle)handle,*(Handle)copy,size);
-
- return copy;
- }
-
- //----------------------------------------------------------------------------------------
- // MMGetHandleSize(MMHandle handle)
- //----------------------------------------------------------------------------------------
-
- size_t MMGetHandleSize(MMHandle handle)
- {
- size_t blkSize;
-
- #if MMDebug
- if( gValidate>0 )
- if( !MMValidateHandle(handle) )
- return 0;
- #endif
-
- blkSize = GetHandleSize((Handle) handle);
- if( MemError() ) {
- MM_WARN("MMGetHandleSize got err %d",MemError());
- blkSize = 0;
- }
- return blkSize;
- }
-
- //----------------------------------------------------------------------------------------
- // MMSetHandleSize(MMHandle handle, size_t blkSize)
- //----------------------------------------------------------------------------------------
-
- MMBoolean MMSetHandleSize(MMHandle handle, size_t blkSize)
- {
- size_t oldSize = ::GetHandleSize((Handle)handle);
-
- if( blkSize == oldSize )
- return kMMTrue;
-
- #if MM_DEBUG
- size_t freePlatformMem = GetFreeTempMemAndAppMem();
- if (freePlatformMem - (blkSize - oldSize) < gHandleMemFullMark)
- return 0;
- #endif
-
- #if MMDebug
- if( blkSize>kMaxHandleBlockSize ) {
- MM_WARN("Bogus blkSize %08lx for MMSetHandleSize",blkSize);
- return kMMFalse;
- }
- if( gValidate>0 ) {
- if( !MMValidateHandle(handle) )
- return kMMFalse;
- // If block will shrink, zap area that will be lost:
- if( blkSize < oldSize )
- memset(OFFSET(*(Handle)handle,blkSize), 0xDD, oldSize-blkSize);
- }
- #endif
-
- SetHandleSize((Handle) handle, blkSize);
- OSErr err = MemError();
- if( err ) {
- if( err!=memFullErr )
- MM_WARN("MMSetHandleSize got err %d",err);
- return kMMFalse;
- }
-
- if( blkSize>oldSize && OutOfAvailableMemoryForHandle(handle,blkSize) ) {
- ::SetHandleSize((Handle)handle,oldSize); // Back out the change
- return kMMFalse;
- }
-
- #if MMDebug
- // If block grew, zap new space at end:
- if( gValidate>0 )
- if( blkSize > oldSize )
- memset(OFFSET(*(Handle)handle,oldSize),0xBB,(size_t)(blkSize-oldSize)); // Fill new space with BB
- #endif
-
- return kMMTrue;
- }
-
- //----------------------------------------------------------------------------------------
- // MMLockHandle(MMHandle handle)
- //----------------------------------------------------------------------------------------
-
- void* MMLockHandle(MMHandle handle)
- {
- #if MMDebug
- if( gValidate>0 )
- if( !MMValidateHandle(handle) )
- return kODNULL;
- #endif
-
- HLock((Handle) handle);
- OSErr err = MemError();
- if( err ) {
- MM_WARN("MMLockHandle got err %d",err);
- return kMMNULL;
- }
-
- return *(Handle) handle;
- }
-
- //----------------------------------------------------------------------------------------
- // MMUnlockPtr(void* ptr)
- //----------------------------------------------------------------------------------------
-
- void MMUnlockPtr(void* ptr)
- {
- if( ptr==kMMNULL ) {
- MM_WARN("MMUnlockPtr(NULL)!");
- } else {
- MMHandle handle = (MMHandle) RecoverHandle((Ptr) ptr);
- if( MemError() )
- MM_WARN("MMUnlockPtr(%p) got err %d",ptr,MemError());
- else if (handle != kMMNULL) {
- #if MMDebug
- if( HGetState((Handle)handle) & 0x80) )
- MM_WARN("MMUnlockPtr(%p): Hdl %p already unlocked",ptr,h);
- #endif
- HUnlock((Handle) handle);
- }
- }
- }
-
- //----------------------------------------------------------------------------------------
- // MMUnlockHandle(MMHandle handle)
- //----------------------------------------------------------------------------------------
-
- void MMUnlockHandle(MMHandle handle)
- {
- #if MMDebug
- if( gValidate>0 )
- if( !MMValidateHandle(handle) )
- THROW(kMMErrMemoryProblem);
- #endif
-
- HUnlock((Handle) handle);
- if( MemError() )
- MM_WARN("MMUnlockHandle(%p) got err %d",handle,MemError());
- }
-
-
- //----------------------------------------------------------------------------------------
- // MMSystemFreeSpace
- //----------------------------------------------------------------------------------------
-
- void MMSystemFreeSpace( MMHeapLocation loc, size_t *total, size_t *contig )
- {
- size_t tempTotal, tempContig;
- if( !total ) total = &tempTotal;
- if( !contig) contig= &tempContig;
-
- Zone *zone = kMMNULL;
-
- switch( loc ) {
- case kMMSysMemory:
- zone = SystemZone();
- break;
-
- case kMMAppMemory:
- zone = ApplicationZone();
- break;
-
- case kMMTempMemory: {
- zone = TempMemZone();
- if( !zone ) { // no memory to find temp zone! must be full!
- *total = *contig = 0;
- return;
- }
- }
- }
- MMSystemFreeSpace(zone,total,contig);
- }
-
-
- static void MMSystemFreeSpace( Zone *zone, size_t *total, size_t *contig )
- {
- if( zone ) {
- Zone *curZone = GetZone();
- SetZone(zone);
-
- *total = FreeMem();
- *contig = MaxBlock();
- size_t purgeTotal, purgeContig;
- PurgeSpace((long*)&purgeTotal,(long*)&purgeContig);
- if( purgeTotal > *total )
- *total = purgeTotal;
- if( purgeContig > *contig )
- *contig = purgeContig;
-
- SetZone(curZone);
- } else
- *total = *contig = 0;
- }
- #if MM_DEBUG
- //------------------------------------------------------------------------------
- // GetFreeTempMemAndAppMem
- //
- // It seems that nobody is allocating handles in the system anymore, so I don't
- // really handle that case here.
- //------------------------------------------------------------------------------
-
- static size_t GetFreeTempMemAndAppMem()
- {
- size_t freeAppHeap;
- size_t freeTempMem;
- size_t ignore;
-
- MMSystemFreeSpace(ApplicationZone(), &freeAppHeap, &ignore);
- MMSystemFreeSpace(TempMemZone(), &freeTempMem, &ignore);
-
- return freeAppHeap + freeTempMem;
- }
-
- //------------------------------------------------------------------------------
- // MMSetHandleMemFullMark
- //------------------------------------------------------------------------------
-
- void MMSetPlatformHandleMemFullMark()
- {
- gHandleMemFullMark = GetFreeTempMemAndAppMem();
- }
-
- void MMUnsetPlatformHandleMemFullMark()
- {
- gHandleMemFullMark = 0;
- }
- #endif /* MM_DEBUG */